#include	"../include/Strings.h"
#include	<cstring>

template<> bool Parse<bool>(const std::string & source) {
	if (source.size() == 0) return false;

	std::string r = ToUpper(source);
	if (r == "TRUE" || r == "T") return true;
	if (r == "FALSE" || r == "F") return false;
	return atol(source.c_str()) != 0;
}

template<> int8_t Parse<int8_t>(const std::string & source) {
	return atol(source.c_str()) & 0xFF;
}

template<> int16_t Parse<int16_t>(const std::string & source) {
	return atol(source.c_str()) & 0xFFFF;
}

template<> int32_t Parse<int32_t>(const std::string & source) {
	return atol(source.c_str());
}

template<> int64_t Parse<int64_t>(const std::string & source) {
	return atoll(source.c_str());
}

template<> uint8_t Parse<uint8_t>(const std::string & source) {
	return (uint16_t)(atol(source.c_str()) & 0xFF);
}

template<> uint16_t Parse<uint16_t>(const std::string & source) {
	return (uint16_t)(atol(source.c_str()) & 0xFFFF);
}

template<> uint32_t Parse<uint32_t>(const std::string & source) {
	return (uint32_t)atol(source.c_str());
}

template<> uint64_t Parse<uint64_t>(const std::string & source) {
	return (uint64_t)atoll(source.c_str());
}

template<> float Parse<float>(const std::string & source) {
	return (float)atof(source.c_str());
}

template<> double Parse<double>(const std::string & source) {
	return atof(source.c_str());
}

template<> const char * Parse<const char *>(const std::string & source) {
	return source.c_str();
}

template<> std::string Parse<std::string>(const std::string & source) {
	return source;
}

std::string ToString(bool b) { return b ? "T" : "F"; }
std::string ToString(int8_t n) { return std::to_string(n); }
std::string ToString(int16_t n) { return std::to_string(n); }
std::string ToString(int32_t n) { return std::to_string(n); }
std::string ToString(int64_t n) { return std::to_string(n); }
std::string ToString(uint8_t n) { return std::to_string(n); }
std::string ToString(uint16_t n) { return std::to_string(n); }
std::string ToString(uint32_t n) { return std::to_string(n); }
std::string ToString(uint64_t n) { return std::to_string(n); }
std::string ToString(float f) { return std::to_string(f); }
std::string ToString(double d) { return std::to_string(d); }
std::string ToString(const char * s) { return std::string(s); }
std::string ToString(const std::string & s) { return s; }

std::string ToLower(const std::string & source) {
	std::string ret = source;
	for (size_t i = 0; i < ret.length(); ++i) {
		if (ret[i] >= 'A' && ret[i] <= 'Z') ret[i] += 32;
	}
	return ret;
}

std::string ToUpper(const std::string & source) {
	std::string ret = source;
	for (size_t i = 0; i < ret.length(); ++i) {
		if (ret[i] >= 'a' && ret[i] <= 'z') ret[i] -= 32;
	}
	return ret;
}

std::string Replace(const std::string & source, const std::string & pattern, const std::string & replace) {
	std::string ret;
	ret.reserve(source.size() * (1 + replace.size()));

	std::string::size_type start = 0;
	std::string::size_type pos = source.find(pattern, start);

	while (pos != std::string::npos) {
		ret.append(source.data() + start, pos - start);
		ret.append(replace);

		start = pos + pattern.size();
		pos = source.find(pattern, start);
	}

	if (start < source.size() - 1) ret.append(source.begin() + start, source.end());
	return ret;
}

std::string TrimStart(const std::string & source, const std::string & trim_chars) {
	std::string ret = source;

	std::string::size_type start = ret.find_first_not_of(trim_chars);
	if (start == std::string::npos) ret = "";
	else ret.erase(0, start);

	return ret;
}

std::string TrimEnd(const std::string & source, const std::string & trim_chars) {
	std::string ret = source;

	std::string::size_type start = ret.find_last_not_of(trim_chars);
	if (start == std::string::npos) ret = "";
	else ret.erase(start + 1);

	return ret;
}

std::string Trim(const std::string & source, const std::string & trim_chars) {
	std::string r = source;
	std::string::size_type start = r.find_first_not_of(trim_chars);
	std::string::size_type end = r.find_last_not_of(trim_chars);

	if (start == std::string::npos) r = "";
	else r = r.substr(start, end - start + 1);

	return r;
}

std::vector<std::string> Split(const std::string & source, const std::string & delim_chars, bool ignore_empty) {
	std::vector<std::string> ret;

	std::string::size_type start = 0, end = 0;
	while (end < source.size()) {
		char ch = source[end];
		if (delim_chars.find(ch) != std::string::npos) {
			if (start != end) ret.push_back(source.substr(start, end - start));
			else if (!ignore_empty) ret.push_back("");
			++end;
			start = end;
		} else {
			++end;
		}
	}

	if (start != end) ret.push_back(source.substr(start));
	return ret;
}

std::vector<std::string> Split(const std::string& str, const std::string& separator, int n/* = -1*/){
	if (str.empty()){
		std::vector<std::string> arr;
		return arr;
	}
	std::vector<std::string> arr;
	int pos = 0;
	int newPos = 0;
	int size = separator.size();
	while (std::string::npos != pos){
		pos = str.find(separator, newPos);
		if (std::string::npos == pos || n == 0){
			if (pos > newPos){
				arr.push_back(str.substr(newPos, pos - newPos));
			}
			break;
		}
		else{
			if (pos > newPos){
				arr.push_back(str.substr(newPos, pos - newPos));
			}
			newPos = pos + size;
			--n;
		}
	}
	return arr;
}

bool HasSuffix(const char* str, const char* end){
    bool ret = false;
    if(nullptr == str && nullptr == end) return true;
    if(nullptr == str || nullptr == end) return false;
	int l1 = strlen(str);
	int l2 = strlen(end);
	if (l1 >= l2){
		if (strcmp(str + l1 - l2, end) == 0){
			ret = true;
		}
	}
	return ret;
}
